package com.jyniubi.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jyniubi.base.exception.Assert;
import com.jyniubi.base.result.ResponseEnum;
import com.jyniubi.base.utils.JwtUtils;
import com.jyniubi.core.enums.LendStatusEnum;
import com.jyniubi.core.hfb.FormHelper;
import com.jyniubi.core.hfb.HfbConst;
import com.jyniubi.core.hfb.RequestHelper;
import com.jyniubi.core.mapper.LendItemMapper;
import com.jyniubi.core.pojo.entity.Lend;
import com.jyniubi.core.pojo.entity.LendItem;
import com.jyniubi.core.pojo.entity.UserAccount;
import com.jyniubi.core.pojo.entity.UserInfo;
import com.jyniubi.core.service.LendItemService;
import com.jyniubi.core.service.LendService;
import com.jyniubi.core.service.UserAccountService;
import com.jyniubi.core.service.UserInfoService;
import com.jyniubi.core.utils.LendNoUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 标的出借记录表 服务实现类
 * </p>
 *
 * @author jyzhang
 * @since 2024-04-27
 */
@Service
@Slf4j
public class LendItemServiceImpl extends ServiceImpl<LendItemMapper, LendItem> implements LendItemService {
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private LendService lendService;
    @Resource
    private UserAccountService userAccountService;
    @Override
    public String invest(String token, Long lendId, BigDecimal investAmount) {
        //1.查询用户状态是否被锁定
        Long userId = JwtUtils.getUserId(token);
        UserInfo userInfo = userInfoService.getById(userId);
        Assert.assertTrue(userInfo.getStatus() != 1, ResponseEnum.LOGIN_LOKED_ERROR);
        //2.用户账户余额 账户余额不能小于 投资金额
        UserAccount userAccount
                = userAccountService.getOne(Wrappers.lambdaQuery(UserAccount.class).
                eq(UserAccount::getUserId, userInfo.getId()).
                select(UserAccount::getAmount));
        Assert.assertTrue(userAccount.getAmount().doubleValue()<investAmount.doubleValue(),ResponseEnum.NOT_SUFFICIENT_FUNDS_ERROR);
        //3.标的状态  募资中
        Lend lend = lendService.getById(lendId);
        Assert.assertTrue(!lend.getStatus().equals(LendStatusEnum.INVEST_RUN.getStatus()),ResponseEnum.LEND_INVEST_ERROR);
        //4.标的是否满标 用户本次投资金额+标的已投金额<=标的总金额
        Assert.assertTrue(lend.getAmount().doubleValue() < lend.getInvestAmount().add(investAmount).doubleValue(),ResponseEnum.LEND_FULL_SCALE_ERROR);
        //5.保存记录lend_item
        LendItem lendItem = new LendItem();
        lendItem.setLendItemNo(LendNoUtils.getLendItemNo());
        lendItem.setLendId(lend.getId());
        lendItem.setInvestUserId(userId);
        lendItem.setInvestName(userInfo.getName());
        lendItem.setInvestAmount(investAmount);
        lendItem.setLendYearRate(lend.getLendYearRate());
        lendItem.setInvestTime(new Date());
        lendItem.setLendStartDate(lend.getLendStartDate());
        lendItem.setLendEndDate(lend.getLendEndDate());
        //计算预期收益： 根据标的的不同方式计算 月化率*期数*投资金额
        BigDecimal interestCount = lendService.getInterestCount(investAmount, lendId.toString());
        lendItem.setExpectAmount(interestCount);
        lendItem.setRealAmount(BigDecimal.ZERO);
        lendItem.setStatus(0);
        this.save(lendItem);
        //6.回调
        Map<String, Object> map = new HashMap<>();
        map.put("agentId", HfbConst.AGENT_ID);
        map.put("voteBindCode",userInfo.getBindCode());//投资人hfb账户bindCode
        UserInfo borrowUserInfo = userInfoService.getById(lend.getUserId());
        map.put("benefitBindCode",borrowUserInfo.getBindCode()); //标的借款用户hfb账户
        map.put("agentProjectCode",lend.getLendNo());//投资项目编号
        map.put("agentProjectName",lend.getTitle());
        //
//        lendItem.getLendItemNo()
//        map.put("agentBillNo",LendNoUtils.getLendItemNo());//本次投资的唯一编号
        map.put("agentBillNo",lendItem.getLendItemNo());//本次投资的唯一编号
        map.put("voteAmt",investAmount);//投资金额
        map.put("projectAmt",lend.getAmount());//标的总金额
        map.put("voteFeeAmt","0");//手续费
        map.put("notifyUrl",HfbConst.INVEST_NOTIFY_URL);
        map.put("returnUrl",HfbConst.INVEST_RETURN_URL);
        map.put("timestamp",System.currentTimeMillis());
        map.put("sign", RequestHelper.getSign(map));
        return FormHelper.buildForm(HfbConst.INVEST_URL,map);
    }

    @Override
    public String invetNotify(HttpServletRequest request) {
        //1.验签
        Map<String, Object> map = RequestHelper.switchMap(request.getParameterMap());
        if (!RequestHelper.isSignEquals(map)){
            log.error("投资回调验签失败: {}", JSON.toJSONString(map));
            return "fail";
        };
        //2.返回状态码
        if (!"0001".equals(map.get("resultCode"))){
            log.error("投资业务失败: {}", JSON.toJSONString(map));
            return "fail";
        }
        //保证幂等性： 使用回调传入的 lendItem的编号查询lendItem 如果状态是已支付 不再处理业务
        //3.查询投资记录
        LendItem lendItem = this.getOne(Wrappers.lambdaQuery(LendItem.class).eq(LendItem::getLendItemNo, map.get("agentBillNo")));
        if (lendItem != null){
            if (lendItem.getStatus() == 1){
                return "success";
            }
        } else {
            log.error("投资唯一编号不同，投资失败：{}",JSON.toJSONString(map));
            return "fail";
        }
        //4.验证投资金额是否正确
        if (lendItem.getInvestAmount().doubleValue() != new BigDecimal(map.get("voteAmt").toString()).doubleValue()) {
            log.error("投资金额不一致：{}",JSON.toJSONString(map));
            return "fail";
        }
        //5.更新投资记录的状态为已支付
        lendItem.setStatus(1);
        this.updateById(lendItem);
        //6.更新标的投资人数和已投金额
        Lend lend = lendService.getOne(Wrappers.lambdaQuery(Lend.class).eq(Lend::getId, lendItem.getLendId()));
        lend.setInvestNum(lend.getInvestNum()+1);
        lend.setInvestAmount(lend.getInvestAmount().add(lendItem.getInvestAmount()));
        lendService.updateById(lend);
        //7.冻结用户的投资金额
        //账户 - 投资金额             冻结金额 + 投资金额
        UserAccount userAccount = userAccountService.getOne(Wrappers.lambdaQuery(UserAccount.class).
                eq(UserAccount::getUserId, lendItem.getInvestUserId()));
        userAccount.setAmount(userAccount.getAmount().subtract(lendItem.getInvestAmount()));
        userAccount.setFreezeAmount(userAccount.getFreezeAmount().add(lendItem.getInvestAmount()));
        userAccountService.updateById(userAccount);
        return "success";
    }
}
